﻿using System;
using System.Collections.Generic;
using System.Linq;

using System.Text;

namespace MathLib {
  public  class PopulationModeling {
        private int liveLength;
        public int Period {private set; get;}
        private int groupCount;
        private int populationsCount;

        public Matrix[] PopulationMatrixes { private set; get; }


        public PopulationModeling(int liveLength, int groupCount, int populationsCount) {
            if (liveLength <= 0 || groupCount <= 0)
                throw new Exception("Неверно заданы параметры");

            this.liveLength = liveLength;
            this.groupCount = groupCount;
            this.Period = liveLength / groupCount;
            this.populationsCount = populationsCount;
           
        }

        public PopulationModeling( int groupCount) {
                    this.groupCount = groupCount;
        }


        public Matrix GenerateA() {
            Matrix f = GenerateFertilityRate();
            Matrix m = GenerateMortalityRate();
            
            MatrixA A = new MatrixA(groupCount, f, m);

            return A;
        }



        public Matrix[] GeneratePopulation() {

            Matrix[] P = new Matrix[populationsCount];
            PopulationMatrixes = new Matrix[populationsCount];


            P[0] = GenerateInit();
            for (int i = 0; i < populationsCount - 1; i++) {
                Matrix A = GenerateA();
                Matrix U = GenerateMigrationRate();
                P[i + 1] = A * P[i] + U;
                PopulationMatrixes[i] = A;
            }

            return P;
        }


        public Matrix GenerateInit() {
            Gauss g = new Gauss();
            Matrix v = new Matrix(groupCount, 1);
            if (groupCount == 2) {
                v[0, 0] = g.Next(25589, 19);
                v[1, 0] = g.Next(26634, 15);
            } else if (groupCount == 3) {
                v[0, 0] = g.Next(12300, 15);
                v[1, 0] = g.Next(25550, 15);
                v[2, 0] = g.Next(12200, 12);
            } else if (groupCount == 5) {
                v[0, 0] = g.Next(11300, 15);
                v[1, 0] = g.Next(12550, 15);
                v[2, 0] = g.Next(25200, 12);
                v[3, 0] = g.Next(20342,45);
                v[4, 0] = g.Next(17778,5);
            } else if (groupCount == 10) {
                v[0, 0] = g.Next(11300, 15);
                v[1, 0] = g.Next(12550, 15);
                v[2, 0] = g.Next(12700, 12);
                v[3, 0] = g.Next(18342, 45);
                v[4, 0] = g.Next(17778, 5);
                v[5,0]= g.Next(25987,12);
                v[6,0]= g.Next(28700,12);
                v[7,0]= g.Next(22098,23);
                v[8,0]= g.Next(15892,24);
                v[9, 0] = g.Next(8500,4);
            }
            return v;

        }

        public  Matrix GenerateMigrationRate() {
            Gauss g = new Gauss();
            Matrix v = new Matrix(groupCount, 1);
            if (groupCount == 2) {
                v[0, 0] = g.Next(589, 12);
                v[1, 0] = g.Next(634, 15);
            } else if (groupCount == 3) {
                v[0, 0] = g.Next(300, 15);
                v[1, 0] = g.Next(550, 15);
                v[2, 0] = g.Next(200, 12);
            } else if (groupCount == 5) {
                v[0, 0] = g.Next(300, 15);
                v[1, 0] = g.Next(550, 15);
                v[2, 0] = g.Next(1200, 12);
                v[3, 0] = g.Next(1342, 45);
                v[4, 0] = g.Next(78, 5);
            } else if (groupCount == 10) {
                v[0, 0] = g.Next(150, 15);
                v[1, 0] = g.Next(550, 15);
                v[2, 0] = g.Next(700, 12);
                v[3, 0] = g.Next(642, 45);
                v[4, 0] = g.Next(1378, 5);
                v[5, 0] = g.Next(1987, 12);
                v[6, 0] = g.Next(1700, 12);
                v[7, 0] = g.Next(998, 23);
                v[8, 0] = g.Next(192, 24);
                v[9, 0] = g.Next(100, 4);
            }
            return v;

        }

        private  Matrix GenerateFertilityRate() {
            Gauss g = new Gauss();
            Matrix v = new Matrix(groupCount, 1);
            if (groupCount == 2) {
                v[0, 0] = g.Next(0.4, 0.015);
                v[1, 0] = g.Next(0.56, 0.015);
            } else if (groupCount == 3) {
                v[0, 0] = g.Next(0.2, 0.015);
                v[1, 0] = g.Next(0.55, 0.015);
                v[2, 0] = g.Next(0.3, 0.012);
            } else if (groupCount == 5) {
                v[0, 0] = g.Next(0, 0);
                v[1, 0] = g.Next(0.13, 0.00015);
                v[2, 0] = g.Next(0.45, 0.0012);
                v[3, 0] = g.Next(0.23,0.00015);
                v[4, 0] = g.Next(0, 0);
            } else if (groupCount == 10) {
                v[0, 0] = g.Next(0, 0);
                v[1, 0] = g.Next(0, 0);
                v[2, 0] = g.Next(0.03, 0.012);
                v[3, 0] = g.Next(0.17, 0.015);
                v[4, 0] = g.Next(0.36, 0.05);
                v[5, 0] = g.Next(0.32, 0.012);
                v[6, 0] = g.Next(0.15, 0.012);
                v[7, 0] = g.Next(0, 0);
                v[8, 0] = g.Next(0, 0);
                v[9, 0] = g.Next(0, 0);
            }
            return v;
        }

        private Matrix GenerateMortalityRate() {
            Gauss g = new Gauss();
            Matrix v = new Matrix(groupCount - 1, 1);
            if (groupCount == 2) {
                v[0, 0] = g.Next(0.89, 0.015);

            }
            if (groupCount == 3) {
                v[0, 0] = g.Next(0.9, 0.015);
                v[1, 0] = g.Next(0.89, 0.015);

            } else if (groupCount == 5) {
                v[0, 0] = g.Next(0.8, 0.015);
                v[1, 0] = g.Next(0.99, 0.015);
                v[2, 0] = g.Next(0.95, 0.015);
                v[3, 0] = g.Next(0.89, 0.015);

            } else if (groupCount == 10) {
                v[0, 0] = g.Next(0.8, 0.015);
                v[1, 0] = g.Next(0.85, 0.015);
                v[2, 0] = g.Next(0.87, 0.015);
                v[3, 0] = g.Next(0.9, 0.015);
                v[4, 0] = g.Next(0.91, 0.015);
                v[5, 0] = g.Next(0.99, 0.015);
                v[6, 0] = g.Next(0.97, 0.015);
                v[7, 0] = g.Next(0.89, 0.015);
                v[8, 0] = g.Next(0.89, 0.015);

            }
            return v;
        }

    }
}